﻿using System;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Discovery;
using System.ServiceModel.Routing;
using SsoaFramework.Core.Behaviors;
using SsoaFramework.Core.Other;

namespace SsoaFramework.Core
{
    [DebuggerDisplay("{Name} {Address}")]
    [DataContract]
    public class Service
    {
        [DataMember]
        public string Name { get; private set; }
        public EndpointAddress Address { get { return serviceEndpoint.Address; } }

        readonly ServiceEndpoint metadataEndpoint;
        readonly ServiceEndpoint serviceEndpoint;

        public ServiceEndpoint ServiceEndpoint { get { return serviceEndpoint; } }
        public ServiceEndpoint MetadataEndpoint { get { return metadataEndpoint; } }

        [DataMember]
        public Uri RoutingServicePath { get; set; }
        [DataMember]
        public Uri RoutingMetadataPath { get; private set; }

        [DataMember]
        public Uri ServicePath { get; private set; }
        [DataMember]
        public Uri MetadataPath { get; private set; }
        [DataMember]
        public bool IsRouted { get; set; }

        public Service(EndpointDiscoveryMetadata metadata, Uri servicesAddress, Uri metadataAddress)
        {
            if (metadata.ContractTypeNames.Count != 1)
                throw new NotImplementedException("More then one contract.");

            Name = metadata.ContractTypeNames[0].Name;

            RoutingServicePath  = new Uri(servicesAddress + Name + "/");
            RoutingMetadataPath = new Uri(metadataAddress + Name + "/");

            metadataEndpoint = new ServiceEndpoint(
                ContractDescription.GetContract(typeof(IRequestReplyRouter)),
                MetadataExchangeBindings.CreateMexHttpBinding(),
                new EndpointAddress(metadata.Address + "mex")
                );
            metadataEndpoint.Behaviors.Add(new MetadataBehavior(RoutingServicePath));

            serviceEndpoint = new ServiceEndpoint(
                ContractDescription.GetContract(typeof(IRequestReplyRouter)),
                new WSHttpBinding(),
                new EndpointAddress(metadata.Address.ToString())
                );
            serviceEndpoint.Behaviors.Add(new ServiceBehavior());

            ServicePath = serviceEndpoint.Address.Uri;
            MetadataPath = metadataEndpoint.Address.Uri;

            Log.Instance.Trace(this);
        }

        public override string ToString()
        {
            return
                String.Format(
                    "{0} on address {1}\n\tMetadata endpoint: {2}\n\tService endpoint: {3}\n\tRouting metadata to: {4}\n\tRouting service to: {5}",
                    Name, Address, metadataEndpoint.Address, serviceEndpoint.Address, RoutingMetadataPath, RoutingServicePath);
        }
    }
}
